package com.weijin.web.websocket;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.weijin.model.ChatHistory;
import com.weijin.service.IChatHistoryService;
import com.weijin.service.RedisService.MessageBroadcaster;
import com.weijin.service.RedisService.MessageRankService;
import com.weijin.service.RedisService.OnlineUserService;
import com.weijin.vo.RestResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author WeiJin
 * @Version 1.0
 * @Date 2025/3/18 10:06
 */
@ServerEndpoint("/chat")
@Component
@Slf4j
public class ChatAnnoHandler {


    //    @Resource
    private static IChatHistoryService chatHistoryService;
    private static ObjectMapper objectMapper;
    private static final Map<String, Session> map = new ConcurrentHashMap<>();
    private static OnlineUserService onlineUserService;
    private static MessageRankService rankService;
    private static MessageBroadcaster messageBroadcaster;

    @Autowired
    public void setChatHistoryMapper(IChatHistoryService chatHistoryService) {
        ChatAnnoHandler.chatHistoryService = chatHistoryService;
    }

    @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        ChatAnnoHandler.objectMapper = objectMapper;
    }

    @Autowired
    public void setOnlineUserService(OnlineUserService onlineUserService) {
        ChatAnnoHandler.onlineUserService = onlineUserService;
    }

    @Autowired
    public void setRedisMessageRankService(MessageRankService rankService) {
        ChatAnnoHandler.rankService = rankService;
    }

    @Autowired
    public void setMessageBroadcaster(MessageBroadcaster messageBroadcaster) {
        ChatAnnoHandler.messageBroadcaster = messageBroadcaster;
    }

    @OnOpen
    public void onOpen(Session session) {
        // 获取用户名
        String userName = getUserName(session);
        // 在线用户存储到redis
        onlineUserService.userLogin(userName);
        // 把连接存储到map集合，以sessionId为key session为value
        map.put(userName, session);
        //获取所有在线用户
        Set<String> userList = onlineUserService.getUserList();
        //将所有在线用户广播所有人
        RestResultVo<Set<String>> restResultVo = new RestResultVo<>();
        restResultVo.setStatus(2002);
        restResultVo.setData(userList);
        String s = null;
        try {
            s = objectMapper.writeValueAsString(restResultVo);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        sendAllMessage(s);
        updateOnlineUserSub();
        log.info("[websocket消息] 建立新的ws连接，用户 {} 加入连接， 当前连接总数：{},", userName, map.size());
    }

    @OnClose
    public void onClose(Session session) {
        // 获取断开连接的用户id，并从map集合移除
        String userName = getUserName(session);
        map.remove(userName);
        // 断开连接，从redis中移除
        onlineUserService.userLogout(userName);
        updateOnlineUserSub();
        log.info("[websocket消息] 用户 {} 断开ws连接，当前连接总数：{}", userName, map.size());
    }

    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        log.info("[websocket消息] 收到websocket信息：{}", message);
        // 将内容持久化到数据库
        ChatHistory chatHistory = objectMapper.readValue(message, ChatHistory.class);
        ChatHistory dataChatHistory = chatHistoryService.addChatHistory(chatHistory);
        // 构造响应体
        RestResultVo<ChatHistory> resultVo = new RestResultVo<>();
        // 状态码2000普通聊天内容
        resultVo.setStatus(2000);
        resultVo.setData(chatHistory);
        // 将构造的响应体转为JSON字符串
        String jsonStr = objectMapper.writeValueAsString(resultVo);
        // 判断当前用户是否一分钟发送超过30条信息
        boolean limit = rankService.checkRateLimit(getUserName(session));
        if (limit) {
            // 没超过30条，通过redis广播信息
            messageBroadcaster.broadcast(jsonStr);
            // 更新消息排行榜
            rankService.addMessageCount(dataChatHistory.getSender());
        } else {
            // 超过30条提示用户不能发送太频繁
            RestResultVo<Object> failed = RestResultVo.failed("发送消息太频繁");
            sendOneMessage(session, objectMapper.writeValueAsString(failed));
        }

    }



    /**
     * 更新在线用户订阅
     */
    public void updateOnlineUserSub() {
        Set<String> userList = onlineUserService.getUserList();
        messageBroadcaster.broadcast("online_users:" + String.join(",", userList));
    }

    /**
     * 发送广播信息
     *
     * @param message 发送的信息
     */
    public void sendAllMessage(String message) {
        map.forEach((key, value) -> {
            if (value.isOpen()) {
                try {
                    value.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        log.info("[websocket信息]：发送广播信息：{}", message);
    }


    /**
     * 发送单点信息
     *
     * @param session 连接对象
     * @param message 发送的信息
     */
    public void sendOneMessage(Session session, String message) {
        if (session.isOpen()) {
            try {
                session.getBasicRemote().sendText(message);
                log.info("[websocket信息]：发送单点信息：{}", message);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 行websocket连接对象总获取用户名
     *
     * @param session 连接对象
     * @return 用户名
     */
    private String getUserName(Session session) {
        String[] arr = session.getRequestURI().getQuery().split("=");
        return arr[arr.length - 1];
    }
}
